#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <semaphore.h>
#include <fcntl.h>
#include <string.h>
#include <time.h>
#include <errno.h>

#define MAX_CARS 100
#define MAX_MAILBOXES 100
#define MAX_STRING_LENGTH 256
#define SHM_KEY 0x1234

typedef struct {
    char data[MAX_STRING_LENGTH];
    int write_pos;
    int read_counts[MAX_CARS]; // 每辆车的读指针
    sem_t write_lock;         // 写锁
    sem_t read_lock;          // 读锁
    int readers;              // 当前读者数量
} Mailbox;

typedef struct {
    int car_id;
    char direction;           // 'A'或'B'
    int in_tunnel;            // 是否在隧道中
    int operations[100][3];   // 操作列表
    int op_count;
    char memory[1024];        // 车辆内存
} CarInfo;

typedef struct {
    int max_cars;
    int current_direction;    // 当前通行方向
    int cars_in_tunnel;
    int cars_A_waiting;
    int cars_B_waiting;
    sem_t tunnel_sem;         // 隧道容量信号量
    sem_t direction_sem;      // 方向控制信号量
    Mailbox mailboxes[MAX_MAILBOXES];
} SharedMemory;

void init_shared_memory(SharedMemory *shm, int max_cars, int mailbox_count) {
    shm->max_cars = max_cars;
    shm->current_direction = 0; // 0表示无方向，1表示A->B，2表示B->A
    shm->cars_in_tunnel = 0;
    shm->cars_A_waiting = 0;
    shm->cars_B_waiting = 0;
    
    sem_init(&shm->tunnel_sem, 1, max_cars);
    sem_init(&shm->direction_sem, 1, 1);
    int i,j;
    for (i = 0; i < mailbox_count; i++) {
        memset(shm->mailboxes[i].data, 0, MAX_STRING_LENGTH);
        shm->mailboxes[i].write_pos = 0;
        for (j = 0; j < MAX_CARS; j++) {
            shm->mailboxes[i].read_counts[j] = 0;
        }
        sem_init(&shm->mailboxes[i].write_lock, 1, 1);
        sem_init(&shm->mailboxes[i].read_lock, 1, 1);
        shm->mailboxes[i].readers = 0;
    }
}

void enter_tunnel(SharedMemory *shm, CarInfo *car) {
    printf("Car %d arriving at tunnel from direction %c\n", car->car_id, car->direction);
    
    // 等待方向信号量
    sem_wait(&shm->direction_sem);
    
    if (shm->current_direction == 0) {
        // 隧道空闲，设置方向
        shm->current_direction = (car->direction == 'A') ? 1 : 2;
        printf("Tunnel direction set to %c->%c\n", 
               (shm->current_direction == 1) ? 'A' : 'B',
               (shm->current_direction == 1) ? 'B' : 'A');
    } else if ((shm->current_direction == 1 && car->direction == 'B') ||
               (shm->current_direction == 2 && car->direction == 'A')) {
        // 方向冲突，等待
        if (car->direction == 'A') {
            shm->cars_A_waiting++;
        } else {
            shm->cars_B_waiting++;
        }
        sem_post(&shm->direction_sem);
        
        // 等待方向改变
        while (1) {
            sem_wait(&shm->direction_sem);
            if ((shm->current_direction == 1 && car->direction == 'A') ||
                (shm->current_direction == 2 && car->direction == 'B') ||
                shm->current_direction == 0) {
                break;
            }
            sem_post(&shm->direction_sem);
            usleep(100000); // 等待100ms再检查
        }
        
        if (car->direction == 'A') {
            shm->cars_A_waiting--;
        } else {
            shm->cars_B_waiting--;
        }
        
        if (shm->current_direction == 0) {
            shm->current_direction = (car->direction == 'A') ? 1 : 2;
            printf("Tunnel direction set to %c->%c\n", 
                   (shm->current_direction == 1) ? 'A' : 'B',
                   (shm->current_direction == 1) ? 'B' : 'A');
        }
    }
    
    // 等待隧道容量信号量
    sem_wait(&shm->tunnel_sem);
    shm->cars_in_tunnel++;
    
    sem_post(&shm->direction_sem);
    
    car->in_tunnel = 1;
    printf("Car %d entered tunnel from direction %c. Cars in tunnel: %d\n", 
           car->car_id, car->direction, shm->cars_in_tunnel);
}

void exit_tunnel(SharedMemory *shm, CarInfo *car) {
    sem_wait(&shm->direction_sem);
    
    shm->cars_in_tunnel--;
    sem_post(&shm->tunnel_sem);
    
    // 检查是否需要改变方向
    if (shm->cars_in_tunnel == 0) {
        if ((shm->current_direction == 1 && shm->cars_B_waiting > 0) ||
            (shm->current_direction == 2 && shm->cars_A_waiting > 0)) {
            shm->current_direction = (shm->current_direction == 1) ? 2 : 1;
            printf("Tunnel direction changed to %c->%c\n", 
                   (shm->current_direction == 1) ? 'A' : 'B',
                   (shm->current_direction == 1) ? 'B' : 'A');
        } else {
            shm->current_direction = 0;
            printf("Tunnel is now empty\n");
        }
    }
    
    sem_post(&shm->direction_sem);
    
    car->in_tunnel = 0;
    printf("Car %d exited tunnel from direction %c. Cars in tunnel: %d\n", 
           car->car_id, car->direction, shm->cars_in_tunnel);
}

void read_mailbox(SharedMemory *shm, CarInfo *car, int mailbox_no, int duration) {
    if (!car->in_tunnel) {
        printf("Car %d attempted to read mailbox %d outside tunnel\n", car->car_id, mailbox_no);
        return;
    }
    
    Mailbox *mb = &shm->mailboxes[mailbox_no];
    
    // 获取读锁
    sem_wait(&mb->read_lock);
    mb->readers++;
    if (mb->readers == 1) {
        sem_wait(&mb->write_lock); // 第一个读者获取写锁
    }
    sem_post(&mb->read_lock);
    
    // 模拟读取操作
    printf("Car %d started reading mailbox %d for %d ms\n", car->car_id, mailbox_no, duration);
    usleep(duration * 1000);
    
    // 读取数据
    int read_pos = mb->read_counts[car->car_id];
    if (read_pos < mb->write_pos) {
        char ch = mb->data[read_pos];
        car->memory[strlen(car->memory)] = ch;
        mb->read_counts[car->car_id]++;
        printf("Car %d read '%c' from mailbox %d\n", car->car_id, ch, mailbox_no);
    } else {
        printf("Car %d reached end of mailbox %d\n", car->car_id, mailbox_no);
    }
    
    // 释放读锁
    sem_wait(&mb->read_lock);
    mb->readers--;
    if (mb->readers == 0) {
        sem_post(&mb->write_lock); // 最后一个读者释放写锁
    }
    sem_post(&mb->read_lock);
}

void write_mailbox(SharedMemory *shm, CarInfo *car, int mailbox_no, int duration, const char *str) {
    if (!car->in_tunnel) {
        printf("Car %d attempted to write to mailbox %d outside tunnel\n", car->car_id, mailbox_no);
        return;
    }
    
    Mailbox *mb = &shm->mailboxes[mailbox_no];
    
    // 获取写锁
    sem_wait(&mb->write_lock);
    
    // 模拟写入操作
    printf("Car %d started writing to mailbox %d for %d ms\n", car->car_id, mailbox_no, duration);
    usleep(duration * 1000);
    
    // 写入数据
    int len = strlen(str), i;
    for (i = 0; i < len && mb->write_pos < MAX_STRING_LENGTH - 1; i++) {
        mb->data[mb->write_pos++] = str[i];
    }
    printf("Car %d wrote '%s' to mailbox %d\n", car->car_id, str, mailbox_no);
    
    // 释放写锁
    sem_post(&mb->write_lock);
}

void car_process(SharedMemory *shm, CarInfo *car, int travel_time) {
    // 随机化旅行时间 (±30%)
    int min_time = travel_time * 0.7;
    int max_time = travel_time * 1.3;
    int actual_time = min_time + rand() % (max_time - min_time + 1);
    
    // 进入隧道
    enter_tunnel(shm, car);
    
    // 执行隧道内操作
    int i;
    for (i = 0; i < car->op_count; i++) {
        int op_type = car->operations[i][0];
        int duration = car->operations[i][1];
        int mailbox_no = car->operations[i][2];
        
        if (op_type == 'r') {
            read_mailbox(shm, car, mailbox_no, duration);
        } else if (op_type == 'w') {
            // 简化处理，假设写入固定字符串
            write_mailbox(shm, car, mailbox_no, duration, "test");
        }
    }
    
    // 模拟通过隧道的时间
    usleep(actual_time * 1000);
    
    // 离开隧道
    exit_tunnel(shm, car);
    
    // 打印车辆内存内容
    printf("Car %d memory content: %s\n", car->car_id, car->memory);
    
    exit(0);
}

int main(int argc, char *argv[]) {
    if (argc < 2) {
        printf("Usage: %s <input_file>\n", argv[0]);
        return 1;
    }
    
    FILE *fp = fopen(argv[1], "r");
    if (!fp) {
        perror("Failed to open input file");
        return 1;
    }
    
    // 读取输入参数
    int total_cars, max_cars, travel_time, mailbox_count, segment_size;
    fscanf(fp, "%d %d %d %d %d", &total_cars, &max_cars, &travel_time, &mailbox_count, &segment_size);
    
    // 初始化共享内存
    int shm_id = shmget(SHM_KEY, sizeof(SharedMemory), IPC_CREAT | 0666);
    if (shm_id == -1) {
        perror("shmget failed");
        return 1;
    }
    
    SharedMemory *shm = (SharedMemory *)shmat(shm_id, NULL, 0);
    if (shm == (void *)-1) {
        perror("shmat failed");
        return 1;
    }
    
    init_shared_memory(shm, max_cars, mailbox_count);
    
    // 读取车辆信息
    CarInfo cars[MAX_CARS];
    int i;
    for (i = 0; i < total_cars; i++) {
        int car_id;
        char direction;
        fscanf(fp, "%d %c", &car_id, &direction);
        
        cars[i].car_id = car_id;
        cars[i].direction = direction;
        cars[i].in_tunnel = 0;
        cars[i].memory[0] = '\0';
        cars[i].op_count = 0;
        
        // 读取操作
        char op;
        while (fscanf(fp, " %c", &op) == 1 && op != 'e') {
            if (op == 'r' || op == 'w') {
                int duration, mailbox_no;
                fscanf(fp, "%d %d", &duration, &mailbox_no);
                
                cars[i].operations[cars[i].op_count][0] = op;
                cars[i].operations[cars[i].op_count][1] = duration;
                cars[i].operations[cars[i].op_count][2] = mailbox_no;
                cars[i].op_count++;
                
                if (op == 'w') {
                    // 跳过写入的字符串
                    char str[100];
                    fscanf(fp, "%s", str);
                }
            }
        }
    }
    fclose(fp);
    
    // 创建子进程模拟车辆
    srand(time(NULL));
    for (i = 0; i < total_cars; i++) {
        pid_t pid = fork();
        if (pid == 0) {
            // 子进程
            car_process(shm, &cars[i], travel_time);
        } else if (pid < 0) {
            perror("fork failed");
            return 1;
        }
    }
    
    // 等待所有子进程结束
    for (i = 0; i < total_cars; i++) {
        wait(NULL);
    }
    
    // 清理共享内存
    shmdt(shm);
    shmctl(shm_id, IPC_RMID, NULL);
    
    return 0;
}
